package org.gridgain.internal.h2.vector.tx;

import org.gridgain.internal.h2.value.VersionedValue;
import org.gridgain.internal.h2.vector.MyMVMap;

public class MyRollbackDecisionMaker extends MyMVMap.DecisionMaker<Object[]> {
    private final MyTransactionStore store;
    private final long transactionId;
    private final long toLogId;
    private final MyTransactionStore.RollbackListener listener;
    private MyMVMap.Decision decision;

    MyRollbackDecisionMaker(MyTransactionStore store, long transactionId, long toLogId,
                          MyTransactionStore.RollbackListener listener) {
        this.store = store;
        this.transactionId = transactionId;
        this.toLogId = toLogId;
        this.listener = listener;
    }

    @Override
    public MyMVMap.Decision decide(Object[] existingValue, Object[] providedValue) {
        assert decision == null;
        if (existingValue == null) {
            // normally existingValue will always be there except of db initialization
            // where some undo log entry was captured on disk but actual map entry was not
            decision = MyMVMap.Decision.ABORT;
        } else {
            VersionedValue valueToRestore = (VersionedValue) existingValue[2];
            long operationId;
            if (valueToRestore == null ||
                    (operationId = valueToRestore.getOperationId()) == 0 ||
                    MyTransactionStore.getTransactionId(operationId) == transactionId
                            && MyTransactionStore.getLogId(operationId) < toLogId) {
                int mapId = (Integer) existingValue[0];
                MyMVMap<Object, VersionedValue> map = store.openMap(mapId);
                if (map != null && !map.isClosed()) {
                    Object key = existingValue[1];
                    VersionedValue previousValue = map.operate(key, valueToRestore, MyMVMap.DecisionMaker.DEFAULT);
                    listener.onRollback(map, key, previousValue, valueToRestore);
                }
            }
            decision = MyMVMap.Decision.REMOVE;
        }
        return decision;
    }

    @Override
    public void reset() {
        decision = null;
    }

    @Override
    public String toString() {
        return "rollback-" + transactionId;
    }
}

